#include "utils.h"

#include <QtCore/QString>
#include <QtCore/QTextStream>

#include "CNetworkManager.h"

/*----------------------------------------------------------------------------*/

CNetworkManager::CNetworkManager()
	:	m_net( NULL )
	,	m_isTerminated( false )
{
}


/*----------------------------------------------------------------------------*/


CNetworkManager::~CNetworkManager()
{
	if ( m_net )
		delete m_net;
}


/*----------------------------------------------------------------------------*/


void CNetworkManager::TrainNetwork( const ImageV& _images, int _epoch, double _threshold )
{	
	FANN::training_data trainData;
	trainData.set_train_data( _images.size(), m_net->get_num_input(), m_net->get_num_output(), _images );

	m_isTerminated = false;
	double error = 0.0;	
	unsigned int bitFail = 0;
	for ( int i = 0; i < _epoch; i++ )
	{
		error = m_net->train_epoch( trainData );
		bitFail = m_net->get_bit_fail();
		QString errorString;
		QString bitFailString;
		QTextStream(&errorString)<<"Mean square error: "<<error;
		QTextStream(&bitFailString)<<", bit fail: "<<bitFail;
		emit Progress( errorString+bitFailString );
		if ( error <= _threshold || m_isTerminated )
			break;
	}
	if ( m_isTerminated )
		emit Progress( "Training terminated." );
	else
		emit Progress( "Training successfully done." );
}


/*----------------------------------------------------------------------------*/


void CNetworkManager::CreateNetwork( const UIntV& _neuronsNumber )
{
	if ( m_net )
	{
		m_net->destroy();
		delete m_net;
		m_networkFileName.clear();		
	}

	m_net = new FANN::neural_net();
	m_net->create_standard( _neuronsNumber.size(), &_neuronsNumber.front() );	
	m_net->set_training_algorithm( FANN::TRAIN_BATCH);	
	m_net->set_activation_function_hidden( FANN::SIGMOID_SYMMETRIC );
	m_net->set_activation_function_output( FANN::SIGMOID_SYMMETRIC );
}


/*----------------------------------------------------------------------------*/


bool CNetworkManager::NetworkExists() const
{
	return m_net != NULL;
}


/*----------------------------------------------------------------------------*/


const std::string& CNetworkManager::GetNetworkFileName() const
{
	return m_networkFileName;
}


/*----------------------------------------------------------------------------*/


void CNetworkManager::SaveNetwork( const std::string& _fileName )
{
	m_networkFileName = _fileName;
	m_net->save( _fileName );
}


/*----------------------------------------------------------------------------*/


void CNetworkManager::LoadNetwork( const std::string& _fileName )
{
	m_networkFileName = _fileName;

	if ( m_net )	
		delete m_net;		

	m_net = new FANN::neural_net();
	m_net->create_from_file( _fileName );
}


/*----------------------------------------------------------------------------*/


void CNetworkManager::CloseNetwork()
{
	if ( m_net )
	{
		m_net->destroy();
		delete m_net;
		m_networkFileName.clear();
	}
	m_net = NULL;
}


/*----------------------------------------------------------------------------*/


void CNetworkManager::Terminate()
{
	m_isTerminated = true;
}


/*----------------------------------------------------------------------------*/


QChar CNetworkManager::ClassifyImage( CImage& _image )
{
	fann_type* result = m_net->run( &_image.m_data.front() );

	float maxVal = 0.0;
	int maxId = 0;
	for ( size_t i = 0; i < m_net->get_num_output(); i++ )
	{
		if ( i == 0 || maxVal < result[i] )
		{
			maxVal = result[i];
			maxId = i;
		}
	}
	QChar ch ( (unsigned short)(maxId + 1072) );
	return ch;
}


/*----------------------------------------------------------------------------*/


